package tpf.designer.pattern.course5.structure_pattern2.flyweight_13.compound;

import org.apache.log4j.Logger;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * 享元工厂，通常实现成为单例
 * 加入实现垃圾回收和引用计数的功能
 */
public class FlyweightFactory {

    public static final Logger LOGGER = Logger.getLogger(FlyweightFactory.class);

    private HashMap flies = new HashMap();

    /**
     * 缓存多个flyweight对象
     */
    private Map<String,Flyweight> fsMap = new HashMap<String,Flyweight>();
    /**
     * 用来缓存被共享对象的缓存配置，key值和上面map的一样
     */
    private Map<String,CacheConfModel> cacheConfMap = new HashMap<String,CacheConfModel>();
    /**
     * 用来记录缓存对象被引用的次数，key值和上面map的一样
     */
    private Map<String,Integer> countMap = new HashMap<String,Integer>();
    /**
     * 默认保存6秒钟，主要为了测试方便，这个时间可以根据应用的要求设置
     */
    private final long DURABLE_TIME = 6*1000L;

    /**
     * 获取某个享元被使用的次数
     * @param key 享元的key
     * @return 被使用的次数
     */
    public synchronized int getUseTimes(String key){
        Integer count = countMap.get(key);
        if(count==null){
            count = 0;
        }
        return count;
    }

    private static FlyweightFactory myself = new FlyweightFactory();

    /**
     * 构造函数私有。外界无法访问
     */
    private FlyweightFactory() {
        //启动清除缓存值的线程
        Thread t = new ClearCache();
        t.start();
    }

    /**
     * 静态工厂，向外界提供唯一的实例
     * @return
     */
    public static FlyweightFactory getInstance(){
        return myself;
    }

    /**
     * 复合享元工厂方法，所需状态以参量形式传入
     * 这个参量恰好可以使用String类型
     * 也可以完全使用一个Vector
     * @param compositeState
     * @return
     */
    public Flyweight factory(String compositeState){
        ConcreteCompositeFlyweight compositeFly = new ConcreteCompositeFlyweight();
//        int length = compositeState.length();
//        Character state;
        for (int i = 0; i < compositeState.length(); i++){
//            state = compositeState.charAt(i);
            LOGGER.info("factory(" + compositeState.charAt(i) + ")");
            compositeFly.add(compositeState.charAt(i),this.factory(compositeState.charAt(i)));
        }
        return compositeFly;
    }

    /**
     * 单纯享元工厂方法
     * @param state
     * @return
     */
    public synchronized Flyweight factory(Character state) {
        Flyweight f = fsMap.get(state);
        if (f==null){
            f = new ConcreteFlyweight(state);
            fsMap.put(String.valueOf(state),f);
            //同时设置引用计数
            countMap.put(String.valueOf(state), 1);

            //同时设置缓存配置数据
            CacheConfModel cm = new CacheConfModel();
            cm.setBeginTime(System.currentTimeMillis());
            cm.setForever(false);
            cm.setDurableTime(DURABLE_TIME);

            cacheConfMap.put(String.valueOf(state), cm);
        } else {
            //表示还在使用，那么应该重新设置缓存配置
            CacheConfModel cm = cacheConfMap.get(state);
            cm.setBeginTime(System.currentTimeMillis());
            //设置回去
            this.cacheConfMap.put(String.valueOf(state), cm);
            //同时计数加1
            Integer count = countMap.get(state);
            count++;
            countMap.put(String.valueOf(state), count);
        }
        return f;
        /*if (flies.containsKey(state)){  //检查具有此状态的享元是否已经存在
            //表示还在使用，那么应该重新设置缓存配置
            CacheConfModel cm = cacheConfMap.get(state);
            cm.setBeginTime(System.currentTimeMillis());
            //设置回去
            this.cacheConfMap.put(String.valueOf(state), cm);
            //同时计数加1
            Integer count = countMap.get(state);
            count++;
            countMap.put(String.valueOf(state), count);
            //直接返回
            return (Flyweight)flies.get(state);
        } else {
            //不存在创建新的实例
            Flyweight fly = new ConcreteFlyweight(state);
            //将实例存储在聚集上
            flies.put(state,fly);
            //同时设置引用计数
            countMap.put(String.valueOf(state), 1);

            //同时设置缓存配置数据
            CacheConfModel cm = new CacheConfModel();
            cm.setBeginTime(System.currentTimeMillis());
            cm.setForever(false);
            cm.setDurableTime(DURABLE_TIME);

            cacheConfMap.put(String.valueOf(state), cm);
            return fly;
        }*/
    }

    /**
     * 辅助方法
     */
    public void checkFlyweight(){
//        Flyweight fly;
        int i = 0;
        LOGGER.info("===================checkFlyweight===================");
        for (Object o : fsMap.entrySet()) {
            Map.Entry e = (Map.Entry) o;
            LOGGER.info("享元对象" + (++i) + ":" + e.getKey());
        }
        LOGGER.info("===================checkFlyweight===================");
    }

    /**
     * 删除key对应的享元对象，连带清除对应的缓存配置和引用次数的记录，不对外
     * @param key 要删除的享元对象的key
     */
    private synchronized void removeFlyweight(String key){
        this.flies.remove(key);
        this.cacheConfMap.remove(key);
        this.countMap.remove(key);
    }
    /**
     * 维护清除缓存的线程，内部使用
     */
    private class ClearCache extends Thread{
        public void run(){
            while(true){
                Set<String> tempSet = new HashSet<>();
                Set<String> set = cacheConfMap.keySet();
                for(String key : set){
                    CacheConfModel ccm = cacheConfMap.get(key);
                    //比较是否需要清除
                    if((System.currentTimeMillis() - ccm.getBeginTime()) >= ccm.getDurableTime()){
                        //可以清除，先记录下来
                        tempSet.add(key);
                    }
                }
                //真正清除
                for(String key : tempSet){
                    FlyweightFactory.getInstance().removeFlyweight(key);
                }
                LOGGER.info("now thread="+ fsMap.size() +",flies=="+fsMap.keySet());
                //休息1秒再重新判断
                try {
                    Thread.sleep(1000L);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }



}
